﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.SharePoint.Administration;
using SPContrib.Artifacts.Collections;
using SPContrib.Extensions;

namespace SPContrib.Artifacts.Definitions
{
    /// <summary>
    /// // TODO: document
    /// </summary>
    public class ModuleDefinition : ElementManifestDefinition
    {
        private string _featurepath;
        private List<FileDefinition> _files;
        private ModuleDefinitionCollection _parent;

        /// <summary>
        /// Specifies the type of list to provision to
        /// </summary>
        /// <remarks>xml: List</remarks>
        public int ListType { get; private set; }
        //public string FeatureAndSourcePath
        //{
        //    get
        //    {
        //        return Path.Combine(this.FeaturePath, this.Source);
        //    }
        //}
        ///// <summary>
        ///// Indicates if the module definition has a source
        ///// </summary>
        //public bool HasSourceLocation
        //{
        //    get
        //    {
        //        return string.IsNullOrEmpty(this.Source) == false;
        //    }
        //}
        /// <summary>
        /// Identifies the file set to provision
        /// </summary>
        /// <remarks>xml: Name</remarks>
        public string Name { get; private set; }
        /// <summary>
        /// Specifies the physical path to the file set relative to the feature
        /// </summary>
        /// <remarks>xml: Path</remarks>
        public string PhysicalPath { get; private set; }
        /// <summary>
        /// Specifies the virtual path of the folder/library in which to place the files (f.e. _catalogs/wp)
        /// </summary>
        /// <remarks>xml: Url</remarks>
        public string VirtualPath { get; private set; }

        private ModuleDefinition(ModuleDefinitionCollection parent)
        {
            this._parent = parent;
        }

        internal ModuleDefinition(ModuleDefinitionCollection parent, SPElementDefinition definition)
            :this(parent)
        {
            var xml = definition.AsXml();

            this._featurepath = definition.FeatureDefinition.RootDirectory;
            this.PhysicalPath = xml.Attribute<string>("Path");
            this.VirtualPath = xml.Attribute<string>("Url");
            this.Name = xml.Attribute<string>("Name");
            this.ListType = xml.Attribute<int>("List");

            this._files = new List<FileDefinition>(
                        from file in xml.Elements("File")
                        where file.Attribute<bool>("IgnoreIfAlreadyExists", false) == true &&
                              file.Attribute<string>("Type", string.Empty) == "GhostableInLibrary"
                        select new FileDefinition(this, file));                      
            
        }

        ///// <summary>
        ///// <para>Specifies the location to a place where the files in the module will be provisioned, as an example '_catalogs/masterpage' would provision the files to the masterpage libary in the _catalogs folder</para>
        ///// <para>This maps to the module's Url attribute</para>
        ///// </summary>
        //public string Destination{ get; set; }
        ///// <summary>
        ///// <para>Specifies a feature relative location to the set of files to provision, as an example 'MyModule\FilesToProvision' would indicate that you have a folder in your module named MyModule called FilesToProvision where the files are placed</para>
        ///// <para>This maps to the module's Path attribute</para>
        ///// </summary>
        //public string Source{ get; set; }
        public void Synchronize()
        {
            // TODO: implement
            // TODO: add logging
            // TODO: add options to sync all stuff or just some stuff via parameters

            foreach (var file in this._files)
            {
                var text = file.SPFile.AsLocalizedString();

            }
        }

        private string ConstructFilePath(string filename)
        {
            return Path.Combine(this._featurepath, filename);
        }
        internal FileInfo FindFileByDefinition(FileDefinition definition)
        { 
            if(File.Exists(this.ConstructFilePath(definition.PhysicalPath)))
            {
                return new FileInfo(this.ConstructFilePath(definition.PhysicalPath));
            }

            throw "File not found"
                    .AsException();
        }
    }
}
